package structures;

import java.io.Serializable;

import javax.swing.JOptionPane;
import javax.swing.JPanel;

import Events.PathEvent;
import Items.Item;

/**
 * Tradepost: Holds Inventory of Items to be sold to a Spaceship that interacts with the Tradepost via
 * the TradepostGUI. Tradepost contains all methods for buying/selling Items to Spaceship. 
 */
@SuppressWarnings("serial")
public class Tradepost extends JPanel implements Serializable{
    private Inventory tradeInventory = new Inventory(), playerInventory;
    private Spaceship ship;
    private int tradeMoneys;
    private int playerMoneys;
    private PathEvent event;
    private double buyRate = 1.0, sellRate = 1.0;
    
    /**
     * Tradepost constructor, no spaceship yet.
     * Sets playerMoneys to -1 and playerInventory to null.
     * 
     */
    public Tradepost(PathEvent event){
    	this.event = event;
        tradeInventory.buildTradePostInventory();
        playerMoneys = -1;
        playerInventory = null;
        tradeMoneys = 10000;
        tradeInventory.setWallet(tradeMoneys);
    }
    
    /**
     * Constructor if you don't have an event for it yet
     * @param inv		Tradepost's inventory
     * @param buyRate	how much the tradepost will buy at compared to base price
     * @param sellRate	how much the tradepost will sell at compared to base price
     */
    public Tradepost(Inventory inv, double buyRate, double sellRate){
    	this(null, inv, buyRate, sellRate);
    }
    
    /**
     * Constructor if you have an event
     * @param e			Event that owns the tradepost
     * @param inv		the inventory
     * @param buyRate	how much of the base price to buy at
     * @param sellRate	how much of the base price to sell at
     */
    public Tradepost(PathEvent e, Inventory inv, double buyRate, double sellRate){
    	this.event = e;
    	tradeInventory = inv;
    	playerMoneys = -1;
    	playerInventory = null;
    	this.buyRate = buyRate;
    	this.sellRate = sellRate;
    }
    
    public Tradepost(PathEvent e, Spaceship s, Inventory inv, double buyRate, double sellRate){
    	this.event = e;
    	tradeInventory = inv;
    	playerMoneys = s.getInventory().getWallet();
    	playerInventory = s.getInventory();
    	this.buyRate = buyRate;
    	this.sellRate = sellRate;
    }
    
    /**
     * Tradepost Contstructor
     * @param ship the ship entering the Inventory
     */
    public Tradepost(Spaceship ship){   
        tradeInventory.buildTradePostInventory();
        playerInventory = ship.getInventory();
        playerMoneys = playerInventory.getWallet();
        tradeMoneys = 10000;
        tradeInventory.setWallet(tradeMoneys);
    }
    
    /**
     * Set the parent event of the Tradepost object.
     */
    public void setEvent(PathEvent e){
    	this.event = e;
    }
    
    /**
     * Ship arrives at Tradepost, set playerInventory and playerMoneys
     * @param ship
     */
    public void addCustomer(Spaceship ship){
        playerInventory = ship.getInventory();
        playerMoneys = playerInventory.getWallet();
        this.ship = ship;
    }
    
    /**
     * A quantity of a certain Item is purchased from tradeInventory, removed from tradeInventory,
     * added to playerInventory
     * @param boughtItem
     * @param quantity
     */
    public void buyItem(Item boughtItem, int quantity){
      // Finally perform the transaction
      adjustQuantity(boughtItem, quantity, tradeInventory, playerInventory);
      tradeMoneys = tradeMoneys + boughtItem.getBasePrice()*quantity;
      playerMoneys = playerMoneys - boughtItem.getBasePrice()*quantity;
      tradeInventory.setWallet(tradeMoneys);
      playerInventory.setWallet(playerMoneys);
    }
    
    /**
     * A quantity of a certain Item is sold to this tradeInventory, removed from playerInventory,
     * added to tradeInventory. Items sold back at half price
     * @param boughtItem
     * @param quantity
     */
    public void sellItem(Item boughtItem, int quantity){
        // Check that the playerInventory actually has enough of the Item they intend to sell
        if (checkQuantity(boughtItem, playerInventory) < quantity) {
            System.out.println("Sorry. You don't enough of those.");
            return;
        }
        if (tradeMoneys < (boughtItem.getBasePrice()/2)*quantity){
            System.out.println("Sorry. We don't have enough money to buy those");
            return;
        }
        // Perform transaction
        if(playerInventory.contains(boughtItem) && 
           checkQuantity(boughtItem, playerInventory) >= quantity) {
            adjustQuantity(boughtItem, quantity, playerInventory, tradeInventory);
            tradeMoneys = tradeMoneys - (boughtItem.getBasePrice() / 2)*quantity;
            playerMoneys = playerMoneys + (boughtItem.getBasePrice() / 2)*quantity;
            tradeInventory.setWallet(tradeMoneys);
            playerInventory.setWallet(playerMoneys);
        }
    }
    
    /**
     * Item/money transaction takes place based on inputed quantity array for Items purchased
     * @param quantities an array of quantities to be purchased
     * @return true if the all transactions were performed successfully
     */
    public boolean buyItems(int[] quantities) {
        int totalCost = 0;
        int totalKleptons = 0;
        // calculate total cost and kleptons of transaction
        for (int i = 0; i < quantities.length; i++) {
            // Check that tradepost has enough of inputed Item
            if (checkQuantity(tradeInventory.get(i), tradeInventory) < quantities[i]) {
                JOptionPane.showMessageDialog(this, "Sorry. I don't have that many " +
                        tradeInventory.get(i).toString(), "Woops!", JOptionPane.WARNING_MESSAGE);
                //System.out.println("Sorry. I don't have that many.");
                return false;
            }
            totalCost += playerInventory.get(i).getBasePrice()*quantities[i];
            totalKleptons += playerInventory.get(i).getKlepton()*quantities[i];
        }
        // Check that the total cost of the inputted Items does not exceed the player wallet
        if (!playerInventory.checkWallet(totalCost)) {
            JOptionPane.showMessageDialog(this, "You don't have enough money!", 
                    "Woops!", JOptionPane.WARNING_MESSAGE);
            //System.out.println("You don't have enough money!");
            return false;
        }
        // Check that the total kleptons of the inputted Items does not exceed the max klepton limit of the ship
        if (!ship.checkKleptonLimit(totalKleptons)){
            JOptionPane.showMessageDialog(this, "You don't have room on your ship for all of that!", 
                    "Woops!", JOptionPane.WARNING_MESSAGE);
            //System.out.println("You don't have room on your ship for all of that!");
            return false;
        }
        // buy items if conditions satisfied
        for (int i = 0; i < quantities.length; i++) {
            buyItem(tradeInventory.get(i), quantities[i]);
        }
        return true;
    }
    
    /**
     * Adjust the respective quantities of the provider and recipient Inventories, based upon
     * the Item bought and the quantity. Note that each Item object holds the quantity for it in
     * its Inventory.
     * @param boughtItem
     * @param quantity
     * @param provider
     * @param recipient
     */
    public void adjustQuantity(Item boughtItem, int quantity, Inventory provider, Inventory recipient){
        provider.removeItem(boughtItem, quantity);
        recipient.addItem(boughtItem, quantity);
    }
    
    /**
     * Returns the quantity of inputed Item in the provider's Inventory
     * @param boughtItem
     * @param provider
     * @return the quantity of the inputed Item type in the provider Inventory
     */
    public int checkQuantity(Item boughtItem, Inventory provider){
        return provider.getQuantity(boughtItem);
    }
    
    /**
     * Getter for the trade inventory
     * @return tradeInventory
     */
    public Inventory getInventory(){
        return tradeInventory;
    }
    
    /**
     * Trade Money Accessor
     * @return tradeMoneys
     */
    public int getTradeMoney(){
        return tradeMoneys;
    }
    
    /**
     * Trade Money Mutator
     * @param tradeMoneys the intended money of this Tradepost
     */
    public void setTradeMoney(int tradeMoneys) {
        this.tradeMoneys = tradeMoneys;
    }
    
    /**
     * Player Money Accessor
     * @return playerMoneys
     */
    public int getPlayerMoney(){
        return playerMoneys;    
    }
    
    /**
     * Event Accessor
     * @return event
     */
    public PathEvent getEvent(){
    	return event;
    }
    
    public int getPlayerKleptons(){
    	return ship.getKleptonLimit();
    }
    
    public Inventory getPlayerInventory(){
    	return playerInventory;
    }
    
    /**
     * Prints the Inventory info for both this Tradepost and the player
     */
    public void testprint(){
    	System.out.println(playerMoneys);
    	System.out.println(playerInventory);
    	System.out.println(tradeMoneys);
    	System.out.println(tradeInventory);
    }
    
}